﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.IO;
using System.Globalization;
using debugger;
using SDcard;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Net.Sockets;
using System.Net;

namespace WindowsFormsApplication1
{

    public sealed partial class Form1 : Base
    {
        public static uint CACHE_CTL = 0x42000000;

        public const byte HALT_UART0 = 0x10;
        public const byte HALT_UART1 = 0x11;
        public const byte DEBUG_RESET_N0 = 0x12;
        public const byte DEBUG_RESET_N1 = 0x13;
        public const byte DEBUG_STEP = 0x14;
        public const byte SET_BYTE_ENABLE = 0x85;
        public const byte SET_DEBUG_ADDRESS = 0x86;
        public const byte SET_DEBUG_WRITEDATA = 0x87;
        public const byte SET_DEBUG_READ_LINE_BASE_ADDR = 0x88;
        public const byte SET_DEBUG_FLG = 0x89;

        public const byte GET_DEBUG8 = 0x20;
        public const byte GET_DEBUG32 = 0x21;
        public const byte GET_ACCESS_TIME = 0x22;
        public const byte GET_ECHO = 0x93;
        public const byte GET_CONST_ECHO = 0x24;
        public const byte GET_PC_RECORD_DATA = 0x25;
        public const byte GET_PC_RECORD_INDEX = 0x26;
        public const byte GET_MISC = 0x27;
        public const byte GET_IRQ_ADDR = 0x28;
        public const byte GET_CPU_ADDRESS = 0x29;
        public const byte GET_PC = 0x2A;
        public const byte GET_PRIVATE_OFFSET = 0x2B;
        public const byte GET_PC_RESULT = 0x2C;
        public const byte GET_CURR_DATA = 0x2D;

        public const byte MEM_READ = 0x30;
        public const byte MEM_WRITE = 0x31;
        public const byte INS_READ = 0x32;
        public const byte MEM_TRANS_READ = 0xA4;
        public const byte MEM_TRANS_WRITE = 0xA5;
        public const byte SEND_BUFF = 0x36;

        public const byte REG_WRITE = 0x48;
        public const byte REG_READ = 0x47;

        public const byte SET_CACHE_DEBUG_INDEX = 0xB0;
        public const byte GET_CACHE_DEBUG_DATA = 0x61;
        public const byte GET_INS_CACHE_DEBUG_DATA = 0x66;
        public const byte GET_FLUSH_COUNT = 0x65;
        public const byte GET_GLICH_COUNT = 0x68;
        public const byte GET_GLICH_COUNT_INS = 0x69;

        public const byte GET_CACHE_CONFIG = 0x67;
        public const byte NOCACHE0 = 0x62;
        public const byte NOCACHE1 = 0x63;
        public const byte GET_CACHE_LIFE_COUNT = 0x64;


        public const byte SPIROM_DEBUG_CS0 = 0x70;
        public const byte SPIROM_DEBUG_CS1 = 0x71;
        public const byte SPIROM_REC = 0x72;
        public const byte SPIROM_SND = 0xC3;
        public const byte SPIROM_SND4 = 0xC4;
        public const byte SPIROM_TRANS_WRITE = 0xC6;

        public const byte RECEIVE_BUFF = 0xF0;

        public Form1()
        {
            InitializeComponent();

            this.FormClosed += new FormClosedEventHandler(Form1_FormClosed);

            this.trackBar1.MouseUp += trackBar1_MouseUp;
            this.trackBar1.MouseDown += trackBar1_MouseDown;

        }

        void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
        }
        string portName;

        private void Form1_Load(object sender, EventArgs e)
        {
            bool ret = connect();

            if (!ret)
            {
                foreach (var item in this.Controls)
                {
                    (item as Control).Enabled = false;
                }
                this.button10.Enabled = true;
                this.textBox3.Enabled = true;
                this.button15.Enabled = true;
                this.textBox4.Enabled = true;
                this.button7.Enabled = true;
            }
            else
            {
                loadSym();
            }
            this.comboBox2.SelectedIndex = 0;

        }



        List<CodeSym> syms;


        private void button4_Click(object sender, EventArgs e)
        {
            try
            {
                getstatus();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public void getCacheDebugData(int id, StringBuilder sb, out uint addr, out uint life, out string invalid, out string dirty, bool isIns = false)
        {
            sendCmd(SET_CACHE_DEBUG_INDEX, (uint)id);
            uint val;
            if (isIns)
            {
                val = sendCmdRet4(GET_INS_CACHE_DEBUG_DATA);
            }
            else
            {
                val = sendCmdRet4(GET_CACHE_DEBUG_DATA);
            }
            //                     16                             1                                15
            //cache_debug_data <= {cache_life[cache_debug_index], cacheInvalid[cache_debug_index], cacheAddrHigh[cache_debug_index]};

            if ((val & 0x80000000) != 0)
            {
                dirty = " D";
            }
            else
            {
                dirty = "  ";
            }
            if ((val & 0x8000) != 0)
            {
                invalid = "  ";
            }
            else
            {
                invalid = " V";
            }
            addr = (val & 0x7fff) << 10;
            if (sb != null)
            {
                sb.Append(dirty + invalid + Util.getHex8((uint)addr));
            }

            life = (val >> 16) & 0x7fff;
            if (sb != null)
            {
                sb.Append(String.Format(",{0: 00}", life));
            }

        }


        public uint getAccessTime()
        {
            return sendCmdRet4(GET_ACCESS_TIME);
        }


        public void getstatus()
        {
            uint temp;
            clearBuff();

            int baseaddr = 0;

            temp = sendCmdRet4(GET_CONST_ECHO);
            if (temp != 0x12345678)
            {
                throw new Exception("checkerror");
            }

            temp = sendCmdRet4(GET_ECHO, 123);
            if (temp != 123)
            {
                throw new Exception("checkerror");
            }

            //sendCmd(SET_TRANSFER_BASE_ADDR, 0);

            StringBuilder sb = new StringBuilder();

            int pc;

            try
            {
                pc = Convert.ToInt32(textBox6.Text, 16);
            }
            catch
            {
                sb.Append("pc:");
                pc = (int)sendCmdRet4(GET_PC);
                sb.Append(Util.getHex8(pc));
            }

            sb.Append("  private_offset:");
            temp = sendCmdRet4(GET_PRIVATE_OFFSET);
            sb.Append(Util.getHex8(temp));

            sb.Append("  pcResult:");
            temp = sendCmdRet4(GET_PC_RESULT);
            sb.Append(Util.getHex8(temp));

            //sb.Append("  last RtypeCmd:");
            //portWrite((byte)(0x18), (byte)0x00); temp = readFromPort(1); sb.Append(Util.getHex2(temp[0]));

            //4        3         2                  1          0
            //halt_cpu,halt_uart,avm_m0_waitrequest,irq_enable,irq_req
            temp = sendCmdRet4(GET_MISC);

            uint halt_cpu = (temp >> 4) & 1;
            sb.Append("  halt_cpu:");
            sb.Append(halt_cpu);

            uint halt_uart = (temp >> 3) & 1;
            sb.Append("  halt_uart:");
            sb.Append(halt_uart);

            sb.Append("  waitRequest:");
            sb.Append((temp >> 2) & 1);

            sb.Append("  waitRequestIns:");
            sb.Append((temp >> 5) & 1);

            sb.Append("  irq_enable:");
            sb.Append((temp >> 1) & 1);

            sb.Append("  irq_req:");
            sb.Append((temp >> 0) & 1);

            sb.Append("  irq_addr:");
            temp = sendCmdRet4(GET_IRQ_ADDR);
            sb.Append(Util.getHex8(temp));

            sb.Append("  cpu_address:");
            temp = sendCmdRet4(GET_CPU_ADDRESS);
            sb.Append(Util.getHex8(temp));


            sb.Append("  curr_data:");
            temp = sendCmdRet4(GET_CURR_DATA);
            sb.Append(Util.getHex8(temp));

            sb.Append("  debugin:");
            temp = sendCmdRet4(GET_DEBUG8);
            sb.Append(Util.getBin8(temp));
            sb.Append("  debugin32:");
            temp = sendCmdRet4(GET_DEBUG32);
            sb.Append(Util.getHex8(temp));

            sb.AppendLine();

            sb.Append("  access time:");
            sb.Append(getAccessTime());
            sb.AppendLine();

            sb.Append("  pc_record_Index:");
            uint pc_index = sendCmdRet4(GET_PC_RECORD_INDEX);
            sb.Append(pc_index);
            sb.AppendLine();
            for (int i = 0; i < 4; i++)
            {
                sb.Append("  pc_record:" + (byte)(pc_index + i - 4) + ",");
                temp = sendCmdRet4(GET_PC_RECORD_DATA, (uint)(pc_index + i - 4));
                sb.Append(Util.getHex8(temp));
                sb.AppendLine();
            }

            sb.Append("cache:");
            temp = sendCmdRet4(GET_CACHE_LIFE_COUNT);
            sb.Append(Util.getHex8(temp));
            sb.Append(" flush count:");
            temp = sendCmdRet4(GET_FLUSH_COUNT);
            sb.Append(Util.getHex8(temp));

            sb.Append(" glich count:");
            temp = sendCmdRet4(GET_GLICH_COUNT);
            sb.Append(Util.getHex8(temp));
            if (temp > 0) { MessageBox.Show("glich"); }

            sb.Append(" glich count ins:");
            temp = sendCmdRet4(GET_GLICH_COUNT_INS);
            sb.Append(Util.getHex8(temp));
            if (temp > 0) { MessageBox.Show("glichIns"); }

            sb.AppendLine();

            temp = sendCmdRet4(GET_CACHE_CONFIG);
            int cache_count = (int)(temp & 0xFF);
            int group_count = (int)((temp >> 8) & 0xFF);

            int cache_count_ins = (int)((temp >> 16) & 0xFF);
            int group_count_ins = (int)((temp >> 24) & 0xFF);


            for (int j = 0; j < group_count; j++)
            {
                sb.Append("Group:" + j + " ");
                for (int i = 0; i < cache_count; i++)
                {
                    //sb.Append(String.Format("{0:00}", i) + ":[");
                    sb.Append(" [");
                    uint life;
                    uint addr;
                    string invalid;
                    string dirty;
                    getCacheDebugData(i * group_count + j, sb, out life, out addr, out invalid, out dirty);
                    sb.Append("] ");
                    //if ((i & 7) == 7) sb.AppendLine();
                }
                sb.AppendLine();
            }

            for (int j = 0; j < group_count_ins; j++)
            {
                sb.Append("GroupIns:" + j + " ");
                for (int i = 0; i < cache_count_ins; i++)
                {
                    //sb.Append(String.Format("{0:00}", i) + ":[");
                    sb.Append(" [");
                    uint life;
                    uint addr;
                    string invalid;
                    string dirty;
                    getCacheDebugData(i * group_count + j, sb, out life, out addr, out invalid, out dirty, true);
                    sb.Append("] ");
                    //if ((i & 7) == 7) sb.AppendLine();
                }
                sb.AppendLine();
            }

            //sb.Append("  numer:"); getreg(0x40, 0, sb);
            //sb.Append("  denom:"); getreg(0x41, 0, sb);
            //sb.Append("  quotient:"); getreg(0x42, 0, sb);
            //sb.Append("  remain:"); getreg(0x45, 0, sb);


            sb.AppendLine();

            if (true && (halt_cpu != 0 || halt_uart != 0))
            {
                int sp = 0;
                getRegArray();
                sb.Append("r0:");
                getreg(0x00, sb);
                sb.Append(" r1:");
                getreg(0x01, sb);

                sb.Append("   r2:");
                getreg(0x02, sb);
                sb.Append(" r3:");
                getreg(0x03, sb);
                sb.AppendLine();

                for (int i = 4; i < 8; i++)
                {
                    sb.Append(" r" + i + ":");
                    getreg((byte)i, sb);
                }
                sb.AppendLine();

                for (int i = 8; i < 16; i++)
                {
                    sb.Append(" r" + i + ":");
                    getreg((byte)i, sb);
                }
                sb.AppendLine();

                for (int i = 16; i < 24; i++)
                {
                    sb.Append(" r" + i + ":");
                    getreg((byte)i, sb);
                }
                sb.AppendLine();

                sb.Append("sp:");
                sp = (int)getreg(27, sb);

                sb.Append("    fp:");
                getreg(28, sb);
                sb.AppendLine();

                sb.Append(" re:");
                getreg(29, sb);

                sb.Append(" ra:");
                getreg(31, sb);
                sb.AppendLine();

                sb.AppendLine("stack: ");
                baseaddr = sp;
                for (int i = -Convert.ToInt32(this.comboBox2.Text) * 4; i < Convert.ToInt32(this.comboBox2.Text) * 4; i += 4)
                {
                    sb.Append((i == 0 ? "*" : " ") + Util.getHex8((uint)(i + baseaddr)) + ":"); getmem((uint)(baseaddr + i), sb); sb.AppendLine();
                }

                baseaddr = 0;
                sb.AppendLine("code: ");
                for (int i = -Convert.ToInt32(this.comboBox2.Text) * 4; i < Convert.ToInt32(this.comboBox2.Text) * 4; i += 4)
                {
                    StringBuilder sb2 = new StringBuilder();
                    uint code = getmem((uint)(pc + i), sb2, true);
                    int target = pc + i;
                    string foundsym = Config.getSym(target, syms);
                    string scode = Config.dasm(syms, cfgs, (uint)code, pc + i, baseaddr);
                    if (i == 0)
                    {
                        sb.AppendLine("----------------------------------------------------------------------------------");
                    }
                    sb.AppendLine((i == 0 ? "*" : " ") + Util.getHex8((uint)(pc + i)) + ":" + scode);
                    if (i == 0)
                    {
                        sb.AppendLine("----------------------------------------------------------------------------------");
                    }
                }

                sb.AppendLine("mem: ");
                baseaddr = Convert.ToInt32(textBox1.Text, 16);
                for (int i = 0; i < Convert.ToInt32(this.comboBox2.Text) * 4 * 2; i += 4)
                {
                    sb.Append("" + Util.getHex8((uint)(baseaddr + i)) + ":"); getmem((uint)(baseaddr + i), sb); sb.AppendLine();
                }
            }

            this.textBox4.Text = sb.ToString();
            Application.DoEvents();
        }

        private void textBox4_TextChanged(object sender, EventArgs e)
        {

        }

        //public int getData(int baseCmd, StringBuilder sb)
        //{
        //	byte[] temp;
        //	int val = 0;
        //	portWrite((byte)(baseCmd + 0x3), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 24; if (sb != null) sb.Append(Util.getHex2(temp[0]));
        //	portWrite((byte)(baseCmd + 0x2), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 16; if (sb != null) sb.Append(Util.getHex2(temp[0]));
        //	portWrite((byte)(baseCmd + 0x1), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 8; if (sb != null) sb.Append(Util.getHex2(temp[0]));
        //	portWrite((byte)(baseCmd + 0x0), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 0; if (sb != null) sb.Append(Util.getHex2(temp[0]));
        //	return val;
        //}

        public uint getmem(uint addr, StringBuilder sb, bool isIns = false)
        {
            sendCmd(SET_DEBUG_ADDRESS, addr);
            uint val;
            if (isIns)
            {
                val = sendCmdRet4(INS_READ);
            }
            else
            {
                val = sendCmdRet4(MEM_READ);
            }
            if (sb != null)
            {
                sb.Append(Util.getHex8(val));
            }
            return val;
        }

        public bool setmem(uint addr, uint data, bool noerr = false, bool no31 = false)
        {
            sendCmd(SET_DEBUG_ADDRESS, addr);
            sendCmd(SET_DEBUG_WRITEDATA, data);

            if (!no31)
            {
                uint temp = sendCmdRet1(MEM_WRITE);
                if (temp != 123)
                {
                    if (!noerr)
                    {
                        throw new Exception("err");
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        private void button2_Click_1(object sender, EventArgs e)
        {

            clearBuff();

            uint addr = Convert.ToUInt32(textBox1.Text, 16);

            //NoCache(addr, checkBox8.Checked);

            StringBuilder sb = new StringBuilder();

            getmem(addr, sb, checkBox2.Checked);

            textBox2.Text = sb.ToString();
            //getstatus();

            uint inc = Convert.ToUInt32(textBox5.Text, 16);
            addr += inc;
            textBox1.Text = Util.getHex8(addr);

        }

        private void button15_Click(object sender, EventArgs e)
        {
            uint addr = Convert.ToUInt32(textBox1.Text, 16);
            this.FlushCache(addr);
        }

        public void writeByteEnable(int byteEnable)
        {
            sendCmd(SET_BYTE_ENABLE, (uint)byteEnable);
        }

        private void button6_Click(object sender, EventArgs e)
        {
            clearBuff();

            int byteEnable = 0;
            byteEnable |= this.checkBox4.Checked ? 8 : 0;
            byteEnable |= this.checkBox5.Checked ? 4 : 0;
            byteEnable |= this.checkBox6.Checked ? 2 : 0;
            byteEnable |= this.checkBox7.Checked ? 1 : 0;
            writeByteEnable(byteEnable);

            uint addr = Convert.ToUInt32(textBox1.Text, 16);
            uint val = Convert.ToUInt32(textBox2.Text, 16);
            setmem(addr, val, false, false);

            uint inc = Convert.ToUInt32(textBox5.Text, 16);
            addr += inc;
            textBox1.Text = Util.getHex8(addr);

            //getstatus();
        }


        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked)
            {
                sendCmd(HALT_UART1);//halt_uart<=1'b1
            }
            else
            {
                sendCmd(HALT_UART0);//halt_uart<=1'b0
            }

        }

        private void button3_Click_1(object sender, EventArgs e)
        {
            sendCmd(DEBUG_STEP);
            getstatus();
        }

        public void clearBuff()
        {
            //connect();
        }
        private void button5_Click(object sender, EventArgs e)
        {
            if (button5.Text == "release")
            {
                close_jtag();
                button5.Text = "connect";
            }
            else
            {
                open_jtag();
                button5.Text = "release";
            }
        }

        private void makeImg()
        {
            String[] files = Directory.GetFiles(@"E:\fpgaproj\mine.new\", "*.bmp");

            foreach (var item in files)
            {
                Bitmap b = new Bitmap(item);

                FileStream fs = new FileStream(item.Replace(".bmp", ".img"), FileMode.CreateNew, FileAccess.Write);
                for (int j = 0; j < b.Height; j++)
                {
                    for (int i = 0; i < b.Width; i++)
                    {
                        uint val = getpixel(b.GetPixel(i, j));
                        fs.WriteByte((byte)val);
                        fs.WriteByte((byte)(val >> 8));
                    }
                }
                fs.Close();
            }
        }

        public static uint getpixel(Color c)
        {
            uint val = 0;
            val += ((uint)(c.R) >> 3) << (5 + 6);
            val += ((uint)(c.G) >> 2) << (5);
            val += ((uint)(c.B) >> 3);
            return val;
        }

        private void setpixel(int x, int y)
        {
            if ((x & 1) == 0)
            {
                setmem((uint)(0x00200000 + x * 2 + y * 2048), 0x0000FFFF);
            }
            else
            {
                setmem((uint)(0x00200000 + x * 2 + y * 2048), (uint)(0x0000FFFF) << 16);
            }
        }
        private void clearpixel(int x, int y)
        {
            if ((x & 1) == 0)
            {
                setmem((uint)(0x00200000 + x * 2 + y * 2048), 0x00000000);
            }
            else
            {
                setmem((uint)(0x00200000 + x * 2 + y * 2048), 0x00000000);
            }
        }

        uint[] data;

        public uint FlushCache(uint addr)
        {
            setmem(CACHE_CTL, 0x80000000 | (addr >> 10));
            getmem(addr, null);
            uint time = this.getAccessTime();
            setmem(CACHE_CTL, 0);
            return time;
        }
        public uint getValue(byte[] arr, int pos)
        {
            uint val = 0;
            val |= arr[(pos << 2) + 0];
            val |= ((uint)arr[(pos << 2) + 1]) << 8;
            val |= ((uint)arr[(pos << 2) + 2]) << 16;
            val |= ((uint)arr[(pos << 2) + 3]) << 24;
            return val;
        }
        bool stop = false;

        private void button7_Click(object sender, EventArgs e)
        {

            /*
            debugport test 
            int ok = 0;
            int ng = 0;
            int ex = 0;
            Random r = new Random();
            byte[] buff = new byte[1024];
            r.NextBytes(buff);
            while (true)
            {
                for (int i = 0; i < 1024; i++)
                {
                    try
                    {
                        portWriteNew((byte)(0x08), buff[i]);
                        uint temp = readFromPort();
                        if (temp != buff[i])
                        {
                            ng++;
                        }
                        else
                        {
                            ok++;
                        }
                    }
                    catch (Exception exc) { 
                        ex++;
                    }
                }
                this.Text = "ok:" + ok + " ng" + ng + " ex:" + ex;
                Application.DoEvents();
                if (stop) {
                    break;
                }
            }
            return;*/


            Form2 form2 = new Form2();
            form2.mainForm = this;
            form2.Show();
        }

        List<Config> cfgs;

        private void loadSym()
        {
            cfgs = Config.loadConfig(@"assembler\config.txt");

            syms = new List<CodeSym>();
            FileStream fs = new FileStream("temp.sym", FileMode.Open, FileAccess.Read);
            StreamReader sw = new StreamReader(fs);
            string s = sw.ReadToEnd();
            sw.Close();
            fs.Close();
            foreach (var line in s.Split('\n'))
            {
                if (line != "")
                {
                    CodeSym sym = new CodeSym();
                    sym.pos = int.Parse(line.Split(',')[0]);
                    sym.name = line.Split(',')[1];
                    syms.Add(sym);
                }
            }
        }


        private void button8_Click(object sender, EventArgs e)
        {

        }

        private void button9_Click(object sender, EventArgs e)
        {
            clearBuff();

            sendCmd(DEBUG_RESET_N0);//debug_reset_n<=1'b0

            Thread.Sleep(100);

            sendCmd(DEBUG_RESET_N1);

        }

        private void button10_Click(object sender, EventArgs e)
        {
            string src = textBox4.Text;
            textBox4.Text = hid(src);
        }

        static string hid(string src)
        {
            string[] arr = src.Split(',');
            int idx = 0;
            int indent = 0;
            int globalUserPage = 0;
            int localUserPage = 0;

            StringBuilder sb = new StringBuilder();
            while (true)
            {
                if (idx >= arr.Length) break;
                string item = arr[idx++];
                int val = Convert.ToInt32(item, 16);
                int len = val & 3;
                if (len == 3) len = 4;
                int type = (val >> 2) & 3;
                int tag = (val >> 4) & 0x0F;
                string stype = "";
                string stag = "";
                string data = "";
                int data0 = 0;

                if (idx < arr.Length)
                {
                    data0 = Convert.ToInt32(arr[idx], 16);
                }
                if (type == 0)
                {
                    stype = "Main";
                    if (tag == 8)
                    {
                        stag = "Input";
                        //Bit 0    {Data (0) | Constant (1)}
                        //Bit 1    {Array (0) | Variable (1)}
                        //Bit 2    {Absolute (0) | Relative (1)}
                        //Bit 3    {No Wrap (0) | Wrap (1)}
                        //Bit 4    {Linear (0) | Non Linear (1)}
                        //Bit 5    {Preferred State (0) | No Preferred (1)}
                        //Bit 6    {No Null position (0) | Nullstate(1)}
                        //Bit 7    Reserved (0)
                        //Bit 8    {Bit Field (0) | Buffered Bytes (1)}
                        //Bit 31-9 Reserved (0)
                        data = Util.getBin8(data0);
                    }
                    else if (tag == 9)
                    {
                        stag = "Output";
                    }
                    else if (tag == 10)
                    {
                        stag = "Collection";
                        //Collection 1010 00 nn 
                        //0x00       Physical (group of axes)
                        if (data0 == 0)
                        {
                            data = "Physical (group of axes)";
                        }
                        //0x01       Application (mouse, keyboard) 
                        if (data0 == 1)
                        {
                            data = "Application (mouse, keyboard) ";
                        }
                        //0x02       Logical (interrelated data) 
                        //0x03       Report 
                        //0x04       Named Array 
                        //0x05       Usage Switch 
                        //0x06       Usage Modifier 
                        //0x07-0x7F  Reserved  
                        //0x80-0xFF  Vendor-defined
                    }
                    else if (tag == 11)
                    {
                        stag = "Feature";
                    }
                    else if (tag == 12)
                    {
                        stag = "End Collection";
                        indent--;
                    }
                    else
                    {
                        stag = "?";
                    }

                }
                else if (type == 1)
                {
                    stype = "Global";
                    if (tag == 0)
                    {
                        stag = "Usage Page";
                        globalUserPage = data0;
                        if (data0 == 0x01) {
                            data = "Generic Desktop Page";
                        }
                        else if (data0 == 0x07)
                        {
                            data = "Keyboard/Keypad Page";
                        }
                        else if (data0 == 0x08)
                        {
                            data = "LED Page";
                        }
                        else if (data0 == 0x09)
                        {
                            data = "Button Page";
                        }
                        else if (data0 == 0x0C)
                        {
                            data = "Consumer Page";
                        }


                    }
                    else if (tag == 1)
                    {
                        stag = "Logical Minimum";
                    }
                    else if (tag == 2)
                    {
                        stag = "Logical Maximum";
                    }
                    else if (tag == 3)
                    {
                        stag = "Physical Minimum";
                    }
                    else if (tag == 4)
                    {
                        stag = "Physical Maximum";
                    }
                    else if (tag == 5)
                    {
                        stag = "Unit Exponent";
                    }
                    else if (tag == 6)
                    {
                        stag = "Unit";
                    }
                    else if (tag == 7)
                    {
                        stag = "Report Size";
                        data = "localUserPage:" + Util.getHex2(localUserPage) + " globalUserPage:" + Util.getHex2(globalUserPage);
                    }
                    else if (tag == 8)
                    {
                        stag = "Report ID";
                    }
                    else if (tag == 9)
                    {
                        stag = "Report Count";
                    }
                    else if (tag == 10)
                    {
                        stag = "Push";
                    }
                    else if (tag == 11)
                    {
                        stag = "Pop";
                    }
                    else
                    {
                        stag = "?";
                    }
                }
                else if (type == 2)
                {
                    stype = "Local";
                    if (tag == 0)
                    {
                        stag = "Usage";
                        if (globalUserPage == 0x01) //Generic Desktop Page
                        {
                            localUserPage = data0;
                            if (data0 == 0x01)
                            { 
                                data = "Pointer";
                            }
                            if (data0 == 0x02)
                            { 
                                data = "Mouse";
                            }
                            if (data0 == 0x06)
                            {
                                data = "Keyboard";
                            }
                            if (data0 == 0x30) { 
                                data = "X";
                            }
                            if (data0 == 0x31) {
                                data = "Y";
                            }
                            if (data0 == 0x38)
                            {
                                data = "Wheel";
                            }
                            if (data0 == 0x80)
                            {
                                data = "System Control";
                            }
                        }
                        else if (globalUserPage == 0x0C)//Consumer Page
                        {
                            localUserPage = data0;
                            if (data0 == 0x01)
                            {
                                data = "Consumer Control";
                            }
                        }
                    }
                    else if (tag == 1)
                    {
                        stag = "Usage Minimum";
                    }
                    else if (tag == 2)
                    {
                        stag = "Usage Maximum";
                    }
                    else if (tag == 3)
                    {
                        stag = "Designator Index";
                    }
                    else if (tag == 4)
                    {
                        stag = "Designator Minimum";
                    }
                    else if (tag == 5)
                    {
                        stag = "Designator Maximum";
                    }
                    else if (tag == 7)
                    {
                        stag = "String Index";
                    }
                    else if (tag == 8)
                    {
                        stag = "String Minimum";
                    }
                    else if (tag == 9)
                    {
                        stag = "String Maximum";
                    }
                    else if (tag == 10)
                    {
                        stag = "Delimiter";
                    }
                    else
                    {
                        stag = "?";
                    }
                }
                else if (type == 3)
                {
                    stype = "Reserved";
                }
                for (int i = 0; i < indent; i++)
                {
                    sb.Append("  ");
                }
                if (type == 0 && tag == 10)
                {
                    indent++;
                }
                if (data != "") {
                    data = "\"" + data + "\"";
                }
                sb.Append(stype + " " + stag + " " + data + " ");
                for (int i = 0; i < len; i++)
                {
                    sb.Append(arr[idx++] + " ");
                }
                sb.AppendLine();
            }
            return sb.ToString();
        }

        private void button11_Click(object sender, EventArgs e)
        {
            clearBuff();

            loadSym();

            sendCmd(HALT_UART1);//halt_uart

            uint baseAddr = 0x00000000;

            loadprog("out.bin");//, baseAddr = 0

            //      end else if (command == 8'h02) begin debug_reset_n<=data[0]; command_done<=1;

            //debug mode
            sendCmd(SET_DEBUG_FLG, 1);


            sendCmd(DEBUG_RESET_N0);//debug_reset_n<=1'b0
            sendCmd(DEBUG_RESET_N1);

            if (!checkBox1.Checked)
            {
                sendCmd(HALT_UART0);//halt_uart<=1'b0
            }
        }
        public void loadprog(string filename)
        {
            FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
            int len = (int)fs.Length;
            int diff = len & 2047;
            len += 2048 - diff;
            byte[] data = new byte[len];
            fs.Read(data, 0, (int)fs.Length);
            fs.Close();

            byte[] buff = new byte[2048];
            for (uint baseAddr = 0; baseAddr < len; baseAddr += 2048)//data.Length
            {
                for (int i = 0; i < 2048; i++) {
                    buff[i] = data[i + baseAddr];
                }
                memBatchWrite(buff, baseAddr);
                FlushCache(baseAddr);
                FlushCache(baseAddr+1024);

                this.Text = baseAddr.ToString();
                Application.DoEvents();
            }
            int err = 0;
            for (uint baseAddr = 0; baseAddr < len; baseAddr += 2048)//data.Length
            {
                memBatchRead(buff, baseAddr);
                for (int i = 0; i < 2048; i++)
                {
                    if (buff[i] != data[i + baseAddr])
                    {
                        err++;
                    }
                }

                this.Text = baseAddr.ToString();
                Application.DoEvents();
            }

            setmem((uint)(CACHE_CTL), 0x40000000);
            setmem(CACHE_CTL, 0);

            //reset reg
            for (int i = 0; i < 2048; i++)
            {
                buff[i] = 0;
            }
            send(buff);

            textBox4.Text = "err:" + err.ToString();
        }

        uint VGA = 0x4C200000;
        uint VGA_MODE = 0x0000;
        uint VGA_BLOCK = 0x0800;
        uint VGA_BASE = 0x1000;
        uint VGA_CURSOR_DATA = 0x1800;
        uint VGA_CURSOR_X = 0x2000;
        uint VGA_CURSOR_Y = 0x2800;
        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            sendCmd(SET_DEBUG_READ_LINE_BASE_ADDR,0x80000000 | (uint)(-trackBar1.Value));
            this.Text = "" + ((uint)(-trackBar1.Value));
        }
        void trackBar1_MouseUp(object sender, MouseEventArgs e)
        {
            sendCmd(SET_DEBUG_READ_LINE_BASE_ADDR, 0);
        }

        void trackBar1_MouseDown(object sender, MouseEventArgs e)
        {
            sendCmd(SET_DEBUG_READ_LINE_BASE_ADDR, 0x80000000 | (uint)(-trackBar1.Value));
        }


        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
        }

        private void checkBox3_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox3.Checked)
            {
                setmem(0x02040000, 0);
            }
            else
            {
                setmem(0x02040000, 2);
            }

        }


        private void checkBox4_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void button16_Click_1(object sender, EventArgs e)
        {
            Form3 form3 = new Form3();
            form3.mainForm = this;
            form3.Show();
            stop = true;
        }

        private void checkBox8_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox8.Checked)
            {
                sendCmd(NOCACHE1);//nocache
            }
            else
            {
                sendCmd(NOCACHE0);//nocache
            }
        }


        uint[] regArray = new uint[32];
        private uint getreg(int index, StringBuilder sb)
        {
            uint val = regArray[index];
            if (sb != null)
            {
                sb.Append(Util.getHex8(val));
            }
            return val;
        }
        private void getRegArray()
        {
            //sendCmd(SET_TRANSFER_BASE_ADDR, 0);
            byte[] data = new byte[128];
            receive(data);

            for (uint i = 0; i < 32; i++)
            {
                uint val = 0;
                val |= data[i * 4];
                val |= (uint)(data[i * 4 + 1] << 8);
                val |= (uint)(data[i * 4 + 2] << 16);
                val |= (uint)(data[i * 4 + 3] << 24);
                regArray[i] = val;
            }
        }


        private void button17_Click(object sender, EventArgs e)
        {
            //sendCmd(SET_TRANSFER_BASE_ADDR, 0);

            byte[] data_buff = new byte[2048];

            Random r = new Random();
            r.NextBytes(data_buff);


            send(data_buff);

            //transfer r
            //8'h22 : begin transferBaseAddr <= ch341a_data; command_ack<=1; end

            byte[] data = new byte[2048];
            receive(data);

            StringBuilder sb = new StringBuilder();
            int err1 = 0;
            int err2 = 0;
            for (uint i = 0; i < 512; i++)
            {
                if ((i & 3) == 0)
                {
                    sb.Append("\r\n" + Util.getHex4((int)i) + ":");
                }

                uint val = 0;
                val |= data[i * 4];
                val |= (uint)(data[i * 4 + 1] << 8);
                val |= (uint)(data[i * 4 + 2] << 16);
                val |= (uint)(data[i * 4 + 3] << 24);

                sb.Append(Util.getHex8(val)); sb.Append(" ");

                uint val2 = 0;
                val2 |= data_buff[i * 4];
                val2 |= (uint)(data_buff[i * 4 + 1] << 8);
                val2 |= (uint)(data_buff[i * 4 + 2] << 16);
                val2 |= (uint)(data_buff[i * 4 + 3] << 24);
                if (val != val2)
                {
                    err1++;
                }

            }

            //for (uint i = 0; i < 512; i++)
            //{
            //    uint val = 0;
            //    val |= data_buff[i * 4];
            //    val |= (uint)(data_buff[i * 4 + 1] << 8);
            //    val |= (uint)(data_buff[i * 4 + 2] << 16);
            //    val |= (uint)(data_buff[i * 4 + 3] << 24);
            //    sendCmdDat(SET_DEBUG_ADDRESS, i);
            //    sendCmdDat(SET_DEBUG_WRITEDATA, val);
            //    sendCmdDat(REG_WRITE);
            //}


            for (uint i = 0; i < 512; i++)
            {
                if ((i & 3) == 0)
                {
                    sb.Append("\r\n" + Util.getHex4((int)i) + ":");
                }
                sendCmd(SET_DEBUG_ADDRESS, i*4);

                uint val = sendCmdRet4(REG_READ);
                sb.Append(Util.getHex8(val));
                sb.Append(" ");
                uint val2 = 0;
                val2 |= data_buff[i * 4];
                val2 |= (uint)(data_buff[i * 4 + 1] << 8);
                val2 |= (uint)(data_buff[i * 4 + 2] << 16);
                val2 |= (uint)(data_buff[i * 4 + 3] << 24);
                if (val != val2)
                {
                    err2++;
                }

            }
            this.textBox4.Text ="batcherr:" + err1 + ", single err:" + err2 + "," + sb.ToString();

        }

        public void memBatchWrite(byte[] data, uint baseAddr)//2k
        {
            send(data);
            sendCmd(SET_DEBUG_ADDRESS, baseAddr);
            uint ret = sendCmdRet1(MEM_TRANS_WRITE, 2048 + baseAddr);
            if (ret != 123)
            {
                throw new Exception();
            }
        }
        public void memBatchRead(byte[] data, uint baseAddr)//2k
        {
            sendCmd(SET_DEBUG_ADDRESS, baseAddr);
            uint ret = sendCmdRet1(MEM_TRANS_READ, 2048 + baseAddr);
            if (ret != 123)
            {
                throw new Exception();
            }

            receive(data);
        }
       

        private void button1_Click(object sender, EventArgs e)
        {
            Random r = new Random();
            int size = 32;
            {
                byte[] alldata = new byte[size * 1024 * 1024];
                r.NextBytes(alldata);

                int err = 0;

                byte[] data_out = new byte[2048];
                //write
                for (uint baseAddr = 0; baseAddr < size * 1024 * 1024; baseAddr += 2048)
                {
                    for (int i = 0; i < 2048; i++)
                    {
                        data_out[i] = alldata[i + baseAddr];
                    }
                    memBatchWrite(data_out, baseAddr);
                    this.Text = "" + baseAddr / 1024;
                }

                byte[] data_in = new byte[2048];
                //read
                for (uint baseAddr = 0; baseAddr < size * 1024 * 1024; baseAddr += 2048)
                {
                    memBatchRead(data_in, baseAddr);
                    for (int i = 0; i < 2048; i++)
                    {
                        if (data_in[i] != alldata[i + baseAddr]) {
                            err++;
                        }
                    }
                    this.Text = "" + baseAddr / 1024;
                }
                this.textBox4.Text = "err:" + err;
            }

            return;
            {
                uint base1 = (uint)(r.Next(32 * 1024 * 1024 / 2048) * 2048);
                byte[] data_buff1 = new byte[2048];

                uint base2 = (uint)(r.Next(32 * 1024 * 1024 / 2048) * 2048);
                byte[] data_buff2 = new byte[2048];

                r.NextBytes(data_buff1);
                r.NextBytes(data_buff2);

                memBatchWrite(data_buff1, base1);
                memBatchWrite(data_buff2, base2);

                //confirm
                int err1 = 0;
                for (uint i = 0; i < 512; i++)
                {
                    uint val = getmem(base1 + i * 4, null);
                    uint val2 = 0;
                    val2 |= data_buff1[i * 4];
                    val2 |= (uint)(data_buff1[i * 4 + 1] << 8);
                    val2 |= (uint)(data_buff1[i * 4 + 2] << 16);
                    val2 |= (uint)(data_buff1[i * 4 + 3] << 24);
                    if (val != val2)
                    {
                        err1++;
                    }
                }
                int err2 = 0;
                for (uint i = 0; i < 512; i++)
                {
                    uint val = getmem(base2 + i * 4, null);
                    uint val2 = 0;
                    val2 |= data_buff2[i * 4];
                    val2 |= (uint)(data_buff2[i * 4 + 1] << 8);
                    val2 |= (uint)(data_buff2[i * 4 + 2] << 16);
                    val2 |= (uint)(data_buff2[i * 4 + 3] << 24);
                    if (val != val2)
                    {
                        err2++;
                    }
                }

                byte[] dataret1 = new byte[2048];
                byte[] dataret2 = new byte[2048];

                memBatchRead(dataret1, base1);
                memBatchRead(dataret2, base2);

                int err3 = 0;
                for (uint i = 0; i < 2048; i++)
                {
                    if (data_buff1[i] != dataret1[i])
                    {
                        err3++;
                    }
                }
                int err4 = 0;
                for (uint i = 0; i < 2048; i++)
                {
                    if (data_buff2[i] != dataret2[i])
                    {
                        err4++;
                    }
                }
                this.textBox4.Text = "err1:" + err1 + " err2:" + err2 + " err3:" + err3 + " err4:" + err4 + "";
            }

        }

        static EventWaitHandle handleA = new AutoResetEvent(false);
        static EventWaitHandle handleB = new AutoResetEvent(false);
        static byte[] data_in;
        static int line;
        static Bitmap bmp;
        static Form4 form;
        static void proc()
        {
            bmp = new Bitmap(1024, 768);
            form = new Form4();
            form.img = bmp;
            //form.Show();
            handleB.Reset();
            handleB.Set();
            for (uint index = 0; index < 1024 * 768 * 2; index += 2048)
            {
                handleA.WaitOne();
                for (int i = 0; i < 2048; i += 2)
                {
                    int b = data_in[i] & 0x1F;
                    int g = ((data_in[i] >> 5) | (data_in[i + 1] << 3)) & 0x3F;
                    int r = data_in[i + 1] >> 3;
                    bmp.SetPixel(i >> 1, line, Color.FromArgb(r << 3, g << 2, b << 3));
                }
                line++;
                form.Refresh();
            }
            bmp.Save(DateTime.Now.ToString("yyyy-MM-dd HH_mm_ss")+".jpg");
            //Application.Run(form);
        }



        private void button8_Click_1(object sender, EventArgs e)
        {
            checkBox1.Checked = true;
            sendCmd(HALT_UART1);

            byte[] save_regs = new byte[2048];
            receive(save_regs);
            uint baseAddr = uint.Parse(textBox7.Text) * 1024;// Convert.ToUInt32(this.textBox1.Text, 16);

            //uint baseAddr = 2048*1024;// Convert.ToUInt32(this.textBox1.Text, 16);
            line = 0;
            data_in = new byte[2048];
            Thread drawthread = new Thread(proc);
            drawthread.Start();
            handleA.Reset();
            handleB.WaitOne();
            for (uint index = 0; index < 1024 * 768 * 2; index += 2048)
            {
                memBatchRead(data_in, index + baseAddr);
                handleA.Set();
                this.Text = "" + index / 1024;
            }

            send(save_regs);
        }


    }
}
